package poset;

import graphs.CycleException;

import java.util.ArrayList;
import java.util.TreeMap;
import java.util.TreeSet;

import spaces.NodeSpace;
import spaces.VectorNode;
import vectors.Vector;

//TODO: Should use Locations and Summables instead of Vectors if possible
public abstract class PosetSpace {
	
	protected String relation;
	protected ArrayList<User> users;
	protected NodeSpace space;
	protected boolean isInitialized = false;
	protected double tension;
	
	public PosetSpace(String relation, ArrayList<User> users) {
		this.relation = relation;
		this.users = users;
	}
	

	public void initialize(){
		TreeSet<VectorNode> nodes = new TreeSet<VectorNode>();
		nodes.addAll(users);
		for(User user : users){
			for(Ordering ordering : user.getPoset(relation).getOrderings()){
				nodes.add(ordering.getItem1());
				nodes.add(ordering.getItem2());
			}
		}
		space = createSpace(nodes);
		for(VectorNode node : nodes){
			node.setPos(randomInitialPosition());	//TODO: What if they don't want it to be random??
		}
		isInitialized = true;
	}


	public void next(){
		if(!isInitialized){
			throw new IllegalStateException("Cannot call next until initialized.");
		}
		tension = 0;
		for(User user : users){
			iterate(user);
		}
	}
	
	protected abstract void iterate(User user);


	//TODO: Make faster by using a safe insert and not inserting Implicitly Redundant orderings somehow
	// This is the real poset present in the space from the user's perspective
	protected Poset createPosetFromDistances(TreeMap<Item,Double> dists){
		Poset poset = new Poset();
		for(Item item1 : dists.keySet()){
			for(Item item2 : dists.keySet()){
				if(dists.get(item2) - dists.get(item1) > getBuffer()){
					try {
						poset.addOrdering(new Ordering(item1, item2));
					} catch (CycleException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (ExplicitRedundancyException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (ReflexiveOrderingException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}
		return poset;
	}
	
	protected abstract TreeMap<Item,Vector> getDifferences(User user);
	
	protected abstract NodeSpace createSpace(TreeSet<VectorNode> nodes);
	
	protected abstract Vector randomInitialPosition();
	
	public abstract double getBuffer();


	public double getTension() {
		return tension;
	}
	
}
